package ws.jdbc.concurrent.driver.sqlserver.cursor.individual;

import ws.jdbc.concurrent.driver.sqlserver.CResultSet;
import ws.jdbc.concurrent.driver.sqlserver.ResultSetCursor;
import java.sql.SQLException;
import java.util.concurrent.locks.ReentrantLock;
import ws.jdbc.concurrent.driver.sqlserver.ResultSetScroll;
import ws.jdbc.concurrent.driver.sqlserver.tds.TDSMessage;
import ws.jdbc.concurrent.driver.sqlserver.tds.TokenCollection;
import static ws.jdbc.concurrent.driver.sqlserver.tds.rpc.StoredProcedures.*;

/**
 * This class provides the functionality of a result set cursor, with individual cache.
 * 
 * @author Wilson Santos, 36228 <wilson.santos@ua.pt>
 */
public abstract class CursorIndividualCache extends ResultSetCursor {

  public CursorIndividualCache(final TDSMessage message, final CResultSet crs, final ReentrantLock lock) throws SQLException {
    super(message, crs, lock);
    /* Create own cache. */
    tdsResultSet = new TokenCollection(tdsResultSet.getCursor(), tdsResultSet.getColumnMetadata());
  }

  @Override
  public void refreshRow() throws SQLException {
    tdsResultSet = message.cursorRefresh(tdsResultSet.getCursor(), currentRow, fetchSize);
    rsIndex = 0;
    forwardCache();
  }

  // XXX maybe delete next and previous while changing the CResultSet version of these methods.
  @Override
  public boolean next() throws SQLException {
    ResultSetScroll next = new ResultSetScroll() {

      public void calcCurrentRow() {
        ++currentRow;
      }

      public void calcRSIndex() {
        ++rsIndex;
      }

      public void resetCache() {
        rsIndex = 0;
        forwardCache();
      }

      public void fetch() throws SQLException {
        tdsResultSet = message.cursorFetch(tdsResultSet.getCursor(), SP_CURSORFETCH_FETCHTYPE_ABSOLUTE, currentRow, fetchSize);
      }
    };
    return scroll(next);
  }

  @Override
  public boolean previous() throws SQLException {
    ResultSetScroll previous = new ResultSetScroll() {

      public void calcCurrentRow() {
        --currentRow;
      }

      public void calcRSIndex() {
        --rsIndex;
      }

      public void resetCache() throws SQLException {
        backwardCache();
      }

      public void fetch() throws SQLException {
        
        int fetchRow = currentRow - fetchSize + 1;
        if (fetchRow < 1) {
          fetchRow = 1;
        }
        tdsResultSet = message.cursorFetch(tdsResultSet.getCursor(), SP_CURSORFETCH_FETCHTYPE_ABSOLUTE, fetchRow, fetchSize);
      }
    };
    return scroll(previous);
  }

  @Override
  public void updateRow() throws SQLException {
    message.cursorMoveAndUpdate(tdsResultSet.getCursor(), currentRow, fetchSize, updateValues);
    /* Update cache with new values. */
    tdsResultSet.updateRow(rsIndex, updateValues);
    cancelRowUpdates();
  }
}